import datetime

from django.db import transaction
from django.db.models import F, Sum, Count
from django.db.models.functions import ExtractMonth
from django.shortcuts import get_object_or_404

from analysis.models import SalesRecord
from oa.views import AppListView, AppCreateView, AppUpdateView, LoginRequiredTemplateView, AppDetailView, Department
from .forms import *


class ManagementView(LoginRequiredTemplateView):
    template_name = 'approval/manage_list.html'


class ProjectListView(AppListView):
    template_name = 'approval/projects.html'
    model = Project

    def get_queryset(self):
        queryset = super().get_queryset()
        search = self.request.GET.get('search')
        if search:
            queryset = queryset.filter(Q(code__icontains=search) | Q(name__icontains=search)).distinct()
        return queryset


class ApplicationListView(AppListView):
    template_name = 'approval/application_list.html'
    model = Application
    paginate_by = 4

    def get_queryset(self):
        queryset = super().get_queryset()
        # 大类分类
        g = self.request.GET.get('g', '1')  # 我的申请
        user_id = self.request.user.id
        if g == '2':  # 待我审批
            queryset = queryset.filter(default_approved_by_id=user_id, status__in=[2])
        elif g == '3':  # 我已审批
            queryset = queryset.filter(default_approved_by_id=user_id, status__gt=2)
        else:  # 我的申请
            queryset = queryset.filter(created_by_id=user_id)
        # 搜索
        search = self.request.GET.get('search')
        if search:
            queryset = queryset.filter(Q(code__icontains=search) | Q(name__icontains=search)).distinct()
        # 审批类型
        t = self.request.GET.get('t')
        if t:
            queryset = queryset.filter(related_application_type_id=int(t))
        # 审批状态
        s = self.request.GET.get('s')
        if s:
            queryset = queryset.filter(status=int(s))
        return queryset

    def get_context_data(self, *, object_list=None, **kwargs):
        context = super().get_context_data(**kwargs)
        # 状态下拉框
        asc_list = list()
        g = self.request.GET.get('g', '')
        if not g:
            g = '1'
        if g == '1':
            for asc in application_status_choices:
                asc_list.append({'pk': asc[0], 'name': asc[1]})
        elif g == '3':
            for asc in application_status_choices:
                if asc[0] > 2:
                    asc_list.append({'pk': asc[0], 'name': asc[1]})
        context['application_status_choices'] = asc_list
        # 总金额统计
        total_approval_amount = self.get_queryset().aggregate(total_amount=Sum('approval_amount'))
        total_amount = 0
        if total_approval_amount:
            total_amount = total_approval_amount['total_amount']
            if not total_amount:
                total_amount = 0
        context['total_amount'] = total_amount
        # 申请类型
        context['related_application_types'] = ApplicationType.objects.all()
        return context


class ApplicationDetailView(AppDetailView):
    template_name = 'approval/application_detail.html'
    model = Application


class ApplicationCreateView(AppCreateView):
    template_name = 'approval/application_add.html'
    model = Application
    form_class = ApplicationCreateForm
    object = None

    def get_success_url(self):
        if self.request.GET:
            if self.request.GET.get('next'):
                return self.request.GET.get('next')
        return reverse('approval:application', args=[self.object.pk])

    def get_context_data(self, **kwargs):
        data = super(ApplicationCreateView, self).get_context_data(**kwargs)
        if self.request.POST:
            data['attachments_formset'] = ApplicationAttachmentFormSet(self.request.POST, self.request.FILES)
        else:
            data['attachments_formset'] = ApplicationAttachmentFormSet()
        return data

    def form_valid(self, form):
        context = self.get_context_data(**self.kwargs)
        attachments_formset = context['attachments_formset']
        with transaction.atomic():
            self.object = form.save()
            if attachments_formset.is_valid():
                attachments_formset.instance = self.object
                attachments_formset.save()
        return super(ApplicationCreateView, self).form_valid(form)


def params_redirect(request, url):
    redirect_params = '?'
    if request.GET:
        for k, v in request.GET.items():
            if v:
                redirect_params += '{}={}&'.format(k, v)
    return '{}{}'.format(url, redirect_params[:-1])


class ApplicationUpdateView(AppUpdateView):
    template_name = 'approval/application_change.html'
    model = Application
    form_class = ApplicationUpdateForm
    object = None

    def get_success_url(self):
        return params_redirect(self.request, reverse('approval:application', args=[self.object.pk]))

    def get_context_data(self):
        data = super(ApplicationUpdateView, self).get_context_data()
        related_application = get_object_or_404(self.model, pk=self.kwargs.get('pk'))
        data['attachments_formset'] = ApplicationAttachmentFormSet(instance=related_application)
        return data

    def form_valid(self, form):
        self.object = form.save()
        attachments_formset = ApplicationAttachmentFormSet(self.request.POST, self.request.FILES, instance=self.object)
        if attachments_formset.is_valid():
            attachments_formset.save()
        return super(ApplicationUpdateView, self).form_valid(form)


class ApplicationSubmitView(AppUpdateView):
    template_name = 'approval/application_detail.html'
    model = Application
    form_class = ApplicationSubmitForm
    object = None

    def get_success_url(self):
        return params_redirect(self.request, reverse('approval:application', args=[self.object.pk]))

    def form_valid(self, form):
        ApprovalRecord.objects.create(
            related_application_id=self.kwargs.get('pk'),
            pre_status=form.initial.get('status'),
            post_status=form.cleaned_data.get('status'),
            related_user_id=self.request.user.id
        )
        self.object = form.save()
        return super().form_valid(form)


class ApplicationApproveView(AppUpdateView):
    template_name = 'approval/application_approve.html'
    model = Application
    form_class = ApplicationApproveForm
    object = None

    def get_success_url(self):
        return params_redirect(self.request, reverse('approval:application', args=[self.object.pk]))

    def form_valid(self, form):
        ApprovalRecord.objects.create(
            related_application_id=self.kwargs.get('pk'),
            pre_status=form.initial.get('status'),
            post_status=form.cleaned_data.get('status'),
            related_user_id=self.request.user.id
        )
        self.object = form.save()
        return super().form_valid(form)


class ProjectUpdateView(AppUpdateView):
    template_name = 'approval/project_change.html'
    model = Project
    form_class = ProjectForm


class ProjectDetailView(AppDetailView):
    template_name = 'approval/project_detail.html'
    model = Project


class CostProfitView(LoginRequiredTemplateView):
    template_name = 'approval/cost_profit.html'

    @staticmethod
    def get_departments():
        departments = Department.objects.order_by('order_index').values('name')
        res = list()
        for department in departments:
            res.append(department['name'])
        return res

    @staticmethod
    def update_month_department(data, d, departments):
        if d['month'] not in data:
            data[d['month']] = dict()
        for department in departments:
            if department not in data[d['month']]:
                data[d['month']][department] = {
                    'application_type': list(),
                    'total_income': 0,
                    'product_costs': 0,
                    'sales_cost': 0,
                    'marketing_cost': 0,
                    'manage_cost': 0,
                    'total_profits': 0
                }
        if d['department'] not in data[d['month']]:
            data[d['month']][d['department']] = {
                'application_type': list(),
                'total_income': 0,
                'product_costs': 0,
                'sales_cost': 0,
                'marketing_cost': 0,
                'manage_cost': 0,
                'total_profits': 0
            }
        return data

    @staticmethod
    def update_profits(data, d):
        data[d['month']][d['department']]['total_profits'] = data[d['month']][d['department']]['total_income'] - \
                                                             data[d['month']][d['department']]['product_costs'] - \
                                                             data[d['month']][d['department']]['sales_cost'] - \
                                                             data[d['month']][d['department']]['marketing_cost'] - \
                                                             data[d['month']][d['department']]['manage_cost']
        return data

    def get_queryset(self):
        sales_record_raw = SalesRecord.objects.exclude(related_customer__need_statistic=False)
        cost_raw = CostSplit.objects.all()
        date_start = self.request.GET.get('date_start')
        date_end = self.request.GET.get('date_end')
        if not date_start:
            date_start = '{0}-01'.format((datetime.datetime.now() - datetime.timedelta(days=90)).strftime('%Y-%m'))
        if date_start:
            sales_record_raw = sales_record_raw.filter(sales_date__gte=date_start)
            cost_raw = cost_raw.filter(record_date__gte=date_start)
        if date_end:
            sales_record_raw = sales_record_raw.filter(sales_date__lte=date_end)
            cost_raw = cost_raw.filter(record_date__lte=date_end)
        sales_record_raw = sales_record_raw.annotate(
            department=F('related_customer__department__name'),
            month=ExtractMonth('sales_date'),
        ).values(
            'department',
            'month',
        ).annotate(
            total_income=Sum('income'),
            product_costs=Sum('cost'),
        ).order_by('month')
        cost_raw = cost_raw.annotate(
            department=F('related_department__name'),
            month=ExtractMonth('record_date'),
            application_type=F('related_application_type__name'),
            category=F('related_application_type__category'),
        ).values(
            'department',
            'month',
            'application_type',
            'category'
        ).annotate(
            sum=Sum('amount'),
        ).order_by('month')
        return sales_record_raw, cost_raw

    @staticmethod
    def calculate_profits(d):
        d['gross_profit_rate'] = round(
            (float(d['total_income']) - float(d['product_costs'])) / float(d['total_income']) * 100, 2)
        d['net_profit_rate'] = round(float(d['total_profits']) / float(d['total_income']) * 100, 2)
        return d

    def get_context_data(self, **kwargs):
        context = super(CostProfitView, self).get_context_data(**kwargs)
        data = dict()
        sales_record_raw, cost_raw = self.get_queryset()
        departments = self.get_departments()
        for d in cost_raw:
            data = self.update_month_department(data, d, departments)
            data[d['month']][d['department']]['application_type'].append(
                {'name': d['application_type'], 'amount': d['sum']}
            )
            if d['category'] == 1:  # 市场费用
                data[d['month']][d['department']]['marketing_cost'] += d['sum']
            elif d['category'] == 2:  # 销售费用
                data[d['month']][d['department']]['sales_cost'] += d['sum']
            elif d['category'] == 3:  # 销售费用
                data[d['month']][d['department']]['manage_cost'] += d['sum']
            data = self.update_profits(data, d)
        for d in sales_record_raw:
            data = self.update_month_department(data, d, departments)
            if d['total_income']:
                data[d['month']][d['department']]['total_income'] += d['total_income']
            if d['product_costs']:
                data[d['month']][d['department']]['product_costs'] += d['product_costs']
            data = self.update_profits(data, d)
        summary = dict()
        summary_sum = {
            'total_income': 0,
            'product_costs': 0,
            'sales_cost': 0,
            'marketing_cost': 0,
            'manage_cost': 0,
            'total_profits': 0
        }
        for month, d in data.items():
            tt = {
                'total_income': 0,
                'product_costs': 0,
                'sales_cost': 0,
                'marketing_cost': 0,
                'manage_cost': 0,
                'total_profits': 0
            }
            fs = ['total_income', 'product_costs', 'sales_cost', 'marketing_cost', 'manage_cost', 'total_profits']
            for k, v in d.items():
                for f in fs:
                    summary_sum[f] += v[f]
                    tt[f] += v[f]
            tt = self.calculate_profits(tt)
            summary[month] = tt
        summary_sum = self.calculate_profits(summary_sum)
        context['data'] = data
        context['summary'] = summary
        context['summary_sum'] = summary_sum
        return context
